package model;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

/**
 * The FileHandler class knows how to open puzzle text files and
 * read them. It is independent of the user interface. A valid puzzle
 * file starts with the number of rows and columns followed by that
 * many rows of letters in that many columns. For instance:
 * 2 3
 * puz
 * zle
 * 
 * Parts of the code are taken from Mark David Weiss's example
 * especially opening the files and handling exceptions
 * @author Beth Katz
 */
public class FileHandler {
	
    private static final int MAXSIZE = 20;
 
    /**
     * Reads the file at fileName and returns the matrix
     * that it contains. Throws IOException if it fails.
     */
    
    public static char [][] matrixFromFileName(String fileName) throws IOException {
    	BufferedReader puzzleStream = openFile(fileName);
    	return readPuzzleFromStream(puzzleStream);
     }
	
    /**
	 * Copied from Weiss
	 * 
	 * Print a prompt and open a file. Retry until open is successful. 
	 * Program exits if end of file is hit.
	 * @param message prompt used to ask user for file
	 */
    private static BufferedReader openFile( String fileName ) throws IOException {
    	FileReader theFile;
    	BufferedReader fileIn = null;

    	if ( fileName == null ) {
    		throw new IOException( "No file name" );
    	}
    	theFile = new FileReader( fileName );
    	fileIn  = new BufferedReader( theFile );

    	return fileIn;
    }

   
    /**
     * Copied from Weiss and adapted substantially to this problem's needs
     * 
     * Reads and checks puzzle sizes and returns puzzle matrix read from file
     */
    private static char[ ][ ]  readPuzzleFromStream(BufferedReader puzzleStream) throws IOException {
        String oneLine;
        int rows;
        int columns;
 
        if( ( oneLine = puzzleStream.readLine( ) ) == null ) {
            throw new IOException( "No lines in puzzle file" );
        }
        
         try
		{
         	StringTokenizer tokenizer = new StringTokenizer(oneLine);
         	rows = Integer.parseInt(tokenizer.nextToken( ));
         	columns = Integer.parseInt(tokenizer.nextToken( ));
		}
        catch ( NoSuchElementException e ) {
            throw new IOException( "Row and column sizes must be on one line" );       		
        }

        if ((rows < 1) || (rows > MAXSIZE) ) {
        		throw new IOException("Rows cannot be " + rows 
            		+ ". It must be between 1 and " + MAXSIZE);
        }
        if ((columns < 1) || (columns > MAXSIZE) ) {
    		throw new IOException("Columns cannot be " + columns 
        		+ ". It must be between 1 and " + MAXSIZE);
        }
        return fillMatrix(puzzleStream,  rows,  columns);
    }

    /**
     * Fills the matrix from puzzleStream with rows lines of columns characters each.
     * @param puzzleStream the opened file potentially containing a puzzle's letters
     * @param rows number of rows in the puzzle
     * @param columns number of columns in the puzzle
     * @return a rows-by-columns array of characters read from the puzzleStream
     * @throws IOException if an input expection occurred
     */
	private static char[ ][ ] fillMatrix(BufferedReader puzzleStream, 
									int rows, int columns)  throws IOException {
		
		char[ ][ ] m = new char [rows] [columns];
		
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < columns; j++) {
				m[i][j] = (char) puzzleStream.read( );
			}
			puzzleStream.readLine( );
		}
		return m;
	}


}
